package com.yuyou.fn.educational.service.impl;

import com.github.wens.framework.service.impl.SuperServiceImpl;
import com.github.wens.mybatisplus.examples.Example;
import com.github.wens.mybatisplus.plugins.Page;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.*;
import com.yuyou.fn.educational.entity.*;
import com.yuyou.fn.educational.mapper.StudentRegMapper;
import com.yuyou.fn.educational.service.*;
import com.yuyou.fn.educational.vo.*;
import com.yuyou.fn.settlement.vo.PayWay;
import org.apache.commons.lang3.Validate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author Terry StudentReg 表数据服务层接口实现类
 */
@Service
public class StudentRegServiceImpl extends SuperServiceImpl<StudentRegMapper, StudentReg, Long> implements IStudentRegService {

    @Resource
    private ICourseClassService courseClassService;


    @Resource
    private ICourseOrderService courseOrderService;



    @Resource
    private IClassLectureService classLectureService ;


    @Resource
    private IChangeClassService changeClassService ;


	@Resource
	private IStudentService studentService;

	@Resource
    private ITeacherService teacherService;

	@Resource
	private IStudentRefundService studentRefundService ;


    /**
	 * 注册列表
	 *
	 * @param studentRegQueryVo
	 * @return
	 */
    @Override
    public List<StudentReg> findStudentRegQuery(StudentRegQueryVo studentRegQueryVo) {
        Example<StudentReg> example = StudentReg.createExample();
        example.orderBy("periodId").desc().orderBy("updateTime").desc();
        Example.Criteria criteria = example.createCriteria();
        criteria.andNotEqualTo("regStatus" , 4 ); //去除无效的
        CriteriaUtils.fillCondition(criteria, studentRegQueryVo);
        return findListByExample(example);
    }


    @Override
    public List<StudentRegDetailVo> toStudentRegDetailVo(List<StudentReg> studentRegList) {
        if(studentRegList.isEmpty()){
            return Collections.EMPTY_LIST ;
        }

        // 取出所有的classId,批量去查
        List<Long> classIds = BeanUtils.toList(studentRegList,"classId");
        List<CourseClass> classList = null;
        List<StudentRegDetailVo> regDetailVoList = null;
        if (classIds.size()>0) {
            classList = courseClassService.findByIds(classIds);

            Map<Long, CourseClass> courseClassMap = BeanUtils.toMap(classList, "classId");
            // 尽量减少查库次数
            regDetailVoList = new ArrayList<>(studentRegList.size());

            for (StudentReg studentReg : studentRegList) {
                StudentRegDetailVo studentRegDetailVo = new StudentRegDetailVo(studentReg,courseClassMap.get(studentReg.getClassId()));
                if (courseClassMap.get(studentReg.getClassId())!=null) {
                    regDetailVoList.add(studentRegDetailVo);
                }
            }
        }
        return regDetailVoList;
    }


    /**
	 * 根据订单编号查询注册信息
	 *
	 * @param courseOrderId
	 * @return
	 */
    @Override
    public List<StudentReg> findStudentRegByCourseOrderId(Long courseOrderId) {
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("courseOrderId" , courseOrderId );
        return findListByExample(example);
    }

    @Override
    public StudentReg findRegByCourseOrderId(long courseOrderId) {
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("courseOrderId" , courseOrderId );
        example.orderBy("createTime").desc();
        return findOneByExample(example);
    }

    @Override
    public void changeStudentRegCharging(Long courseOrderId , Integer chargingStatus , List<PayLecture> payLectures ) {

        List<StudentReg> studentRegList = findStudentRegByCourseOrderId(courseOrderId) ;
        for(int i = 0 ; i < studentRegList.size()  ; i++ ){
            StudentReg studentReg = studentRegList.get(i);

            StudentReg update = new StudentReg();
            update.setRegId(studentReg.getRegId());
            update.setChargingStatus(chargingStatus);//支付状态跟着订单的支付状态
			update.setUpdateTime(TimeUtils.now());
            update.setLastPayTime(TimeUtils.now());
			if (chargingStatus == 2) {// 已经支付
                update.setPayAmount(studentReg.getTotalAmount());
                update.setPayLectureAmount(studentReg.getInitEndAmount() - studentReg.getInitStartAmount() + 1 );
			} else if (chargingStatus == 1 || chargingStatus == 0) {// 欠费
				for(int j = 0 ; j < payLectures.size()  ; j++ ){
				    if(payLectures.get(j).getRegId().equals(studentReg.getRegId()) && payLectures.get(j).getStart() <= payLectures.get(j).getEnd() ){
                        update.setPayAmount(studentReg.getPayAmount().add(payLectures.get(j).getPayAmount()));
                        update.setPayLectureAmount(studentReg.getPayLectureAmount() + ( payLectures.get(j).getEnd() - payLectures.get(j).getStart() + 1 ) );
				        break;
                    }
                }
            }else {
                throw new BusException("What???");
            }
            updateSelectiveById(update) ;
        }


    }



    @Transactional
    @Override
    public void changeClass(Long regId, Integer changeLectureFrom, Long classId, Integer startAmount, Integer endAmount,String reason, Principals.Principal principal) {

        if(principal == null ){
            principal = Principals.getDefaultPrincipal();
        }

        StudentReg studentReg = findById(regId);

        if(studentReg.getChargingStatus() != 2 ){
            throw new BusException("未缴费无法完成转班");
        }

        if(changeLectureFrom < studentReg.getStartAmount() || changeLectureFrom > studentReg.getEndAmount() ){
            throw new BusException("转班讲次超出报名讲次");
        }

        BigDecimal refundAmount = BigDecimals.toFixed2(BigDecimals.calProportion(studentReg.getTotalAmount().subtract(studentReg.getRefundAmount() == null ? BigDecimal.ZERO : studentReg.getRefundAmount() ), new BigDecimal(studentReg.getEndAmount() - changeLectureFrom + 1), new BigDecimal(studentReg.getEndAmount() - studentReg.getStartAmount() + 1)),2  );

        StudentRefundVo studentRefundVo = new StudentRefundVo();
        studentRefundVo.setRefundWay(3);//退到账户
        studentRefundVo.setDescription("转班");
        studentRefundVo.setRegId(regId);
        studentRefundVo.setRefundLectureFrom(changeLectureFrom);
        studentRefundVo.setFinalRefundAmount(refundAmount);
        studentRefundService.saveStudentRefund(studentRefundVo,principal);

        createNewClassCourseOrderForChangeClass(classId,startAmount ,endAmount , studentReg.getStudentId(), refundAmount,studentReg.getCounselorId(), principal);

        Student student=studentService.findById(studentReg.getStudentId());
        ChangeClass changeClass = new ChangeClass();
        changeClass.setBalanceAmount(BigDecimal.ZERO);
        changeClass.setClassId(classId);
        changeClass.setStudentId(student.getStudentId());
        changeClass.setStudentName(student.getName());
        changeClass.setStudentPhoneNo(student.getPhoneNo());
        changeClass.setOldClassId(studentReg.getClassId());
        changeClass.setStartAmount(startAmount);
        changeClass.setEndAmount(endAmount);
        changeClass.setReason(reason);
        changeClass.setRegId(regId);
        changeClass.setOperator(principal.name);
        changeClass.setCreateTime(TimeUtils.now());
        changeClass.setUpdateTime(TimeUtils.now());
        changeClass.setStudyAmount( changeLectureFrom - studentReg.getStartAmount() );
        changeClassService.insertSelective(changeClass);
    }


    private CourseOrder createNewClassCourseOrderForChangeClass(Long classId , Integer startAmount , Integer endAmount, Long studentId, BigDecimal refundAmount,Long counselorId, Principals.Principal principal) {
        CourseClass courseClass = courseClassService.findById(classId,CourseClass.BASE_FIELDS);

        if (courseClass.getCompletedLectureAmount()>=startAmount ){
            throw new BusException("存在讲次已经考勤");
        }
        if (courseClass.getLectureAmount()<endAmount){
            throw new BusException("传入的结束讲次大于班级的结束讲次");
        }
        if (courseClass.getLectureAmount()<startAmount){
            throw new BusException("传入的开始讲次大于班级的结束讲次");
        }

        CreateCourseOrderInfo createCourseOrderInfo = new CreateCourseOrderInfo();
        createCourseOrderInfo.setFrom(2);
        createCourseOrderInfo.setCourseClassList(Arrays.asList(courseClass));
        RegClassInfoVo regClassInfoVo = new RegClassInfoVo();
        regClassInfoVo.setClassId(courseClass.getClassId());
        regClassInfoVo.setStartAmount(startAmount);
        regClassInfoVo.setEndAmount(endAmount);
        regClassInfoVo.setTotalAmount(refundAmount);
        regClassInfoVo.setCounselorId(counselorId);
        createCourseOrderInfo.setRegClassInfoList(Arrays.asList(regClassInfoVo));
        createCourseOrderInfo.setStudent(studentService.findById( studentId));
        CourseOrder courseOrder = courseOrderService.createOrder(createCourseOrderInfo,principal);

        PayInfoOfCourseOrder payInfoOfCourseOrder = new PayInfoOfCourseOrder() ;
        payInfoOfCourseOrder.setPayAmount(refundAmount);
        payInfoOfCourseOrder.setPayWays(Arrays.asList(new PayWay(3,refundAmount,null)));
        payInfoOfCourseOrder.setChargeCampusId(courseClass.getCampusId());
        payInfoOfCourseOrder.setPrincipal(principal);
        courseOrderService.payCourseOrder(courseOrder,payInfoOfCourseOrder);
        return courseOrder;
    }

    /**
	 * 根据注册表id，修改注册状态
	 *
	 * @param regId
	 * @param regStatus（0-在读；1-转班；2-退账户；3-退班退费）
	 */
    @Override
    public void changeRegStatus(Long regId, Integer regStatus) {
        StudentReg studentReg = new StudentReg();
        studentReg.setRegId(regId);
        studentReg.setRegStatus(regStatus);
        studentReg.setUpdateTime(TimeUtils.now());
        updateSelectiveById(studentReg);
    }

    @Override
    public Page<StudentReg> findStudentRegByQuery(StudentRegQueryVo studentRegQueryVo, int pageNo, int pageSize) {
        Example<StudentReg> example = StudentReg.createExample();
        example.orderBy("createTime").desc();
        Example.Criteria criteria = example.createCriteria();
        CriteriaUtils.fillCondition(criteria , studentRegQueryVo);
        return findPageByExample(example,pageNo,pageSize );
    }

    @Override
    public List<StudentReg> findStudentReg(Long classId, Long studentId) {
        Example<StudentReg> example = StudentReg.createExample();
        example.createCriteria().andEqualTo("regStatus" , 0 ).andEqualTo("classId",classId).andEqualTo("studentId",studentId );
        return findListByExample(example) ;
    }


    @Override
    public void changeRefundStatus(Long regId, int status) {
        StudentReg studentReg = new StudentReg();
        studentReg.setRegId(regId);
        studentReg.setRefundStatus(status);
        studentReg.setUpdateTime(TimeUtils.now());
        updateSelectiveById(studentReg);
    }

    @Override
    public void saveStudentReg(final List<StudentReg> studentRegList) {
        if(studentRegList.isEmpty()){
           return;
        }
        insertBatch(studentRegList);
    }


    @Override
    public List<StudentReg> findStudentRegByPeriodIdStudentId(Long periodId, Long studentId) {
        Example<StudentReg> example = StudentReg.createExample();
        example.createCriteria().andEqualTo("regStatus",0).andEqualTo("periodId",periodId ).andEqualTo("studentId" , studentId );
        return findListByExample(example);
    }


    @Override
    public List<StudentReg> findStudentRegByClassId(Long classId) {
        Example<StudentReg> example = StudentReg.createExample();
        example.createCriteria().andEqualTo("regStatus",0).andEqualTo("classId",classId );
        return findListByExample(example);
    }


    @Override
    public List<StudentReg> findStudentRegByAreaTeamIdPeriodIdStudentIds(Long areaTeamId, Long periodId, List<Long> studentIds) {
        if(studentIds.isEmpty()){
            return Collections.EMPTY_LIST ;
        }
        Example<StudentReg> example = StudentReg.createExample();
        example.createCriteria().andEqualTo("regStatus",0).andEqualTo("areaTeamId" , areaTeamId ).andEqualTo("periodId",periodId ).andIn("studentId" , studentIds );
        return findListByExample(example);
    }


    @Transactional
    @Override
    public void cancel(Long regId ){
        final StudentReg studentReg = findById(regId,"studentId","classId","chargingStatus","startAmount","endAmount");
        if(studentReg.getChargingStatus() != 0 ){
			throw new BusException("此学生已经缴费，无法取消，请走退费流程");
        }
        changeRegStatus(regId , 4);
        courseClassService.decreaseRegAmount(studentReg.getClassId());
        classLectureService.deleteAttendanceRecordForStudent(studentReg.getClassId(),studentReg.getRegId(),studentReg.getStartAmount(),studentReg.getEndAmount());

    }





    @Override
    public Long countByPeriodIdStudentIdRegStatus(Long periodId, Long studentId, Integer regStatus) {
        Example<StudentReg> example = StudentReg.createExample();
        example.createCriteria().andEqualTo("periodId",periodId).andEqualTo("studentId",studentId).andEqualTo("regStatus",regStatus);
        return countByExample(example);
    }

    @Override
    public Long countPrevious(List<Long> periodIds, Long studentId, Long areaTeamId, Integer regStatus) {
        if (periodIds==null || periodIds.size()<=0){
            return 0L;
        }
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andIn("periodId",periodIds);
        criteria.andEqualTo("studentId",studentId);
        criteria.andEqualTo("areaTeamId",areaTeamId);
        criteria.andEqualTo("regStatus",regStatus);
        return countByExample(example);
    }

    @Override
    public List<StudentReg> findByPeriods(List<Long> periodIds, Long studentId,Integer regStatus) {
        if (periodIds==null || periodIds.size()<=0 ){
            return Collections.EMPTY_LIST;
        }
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andIn("periodId",periodIds);
        criteria.andEqualTo("studentId",studentId);

        criteria.andEqualTo("regStatus",regStatus);
        return findListByExample(example);
    }

    @Override
    public void updateSenior(List<Long> classIds, Long seniorId, String seniorName) {
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andIn("classId",classIds);
        //criteria.andIsNull("seniorId");
        StudentReg studentReg=new StudentReg();
        studentReg.setSeniorId(seniorId);
        studentReg.setSeniorName(seniorName);
        studentReg.setUpdateTime(TimeUtils.now());
        this.updateSelectiveByExample(studentReg,example);

    }

    @Override
    public void updateSeniorByRegId(Long regId, Long seniorId) {
        Teacher teacher=teacherService.findById(seniorId);
        if (teacher==null){
            throw new BusException("查不到该教师");
        }
        StudentReg studentReg=new StudentReg();
        studentReg.setRegId(regId);
        studentReg.setSeniorId(seniorId);
        studentReg.setSeniorName(teacher.getTeacherName());
        studentReg.setUpdateTime(TimeUtils.now());
        this.updateSelectiveById(studentReg);
    }

    @Override
    public void updateRefundStatus(Long regId, Integer refundStatus) {
        StudentReg studentReg=new StudentReg();
        studentReg.setRegId(regId);
        studentReg.setRefundStatus(refundStatus);
        studentReg.setUpdateTime(TimeUtils.now());
        this.updateSelectiveById(studentReg);
    }

    @Override
    public List<StudentHistoryRegInfoVo> findStudentHistoryRegInfo(Long studentId, List<Long> relPeriodIdList) {
        if(relPeriodIdList == null || relPeriodIdList.size() == 0 ){

        }
        return autoMapper.findStudentHistoryRegInfo(studentId,relPeriodIdList);
    }

    @Transactional
    @Override
    public void refundAndCancel(Long regId, Principals.Principal principal) {
        StudentReg studentReg = findById(regId);
        BigDecimal refundAmount = studentReg.getRefundAmount();
        if(refundAmount == null ){
            refundAmount = BigDecimal.ZERO ;
        }
        BigDecimal payAmount = studentReg.getPayAmount().subtract(refundAmount);//已经支付的金额-已经退费
        StudentRefundVo studentRefundVo = new StudentRefundVo();
        studentRefundVo.setRegId(regId);
        studentRefundVo.setFinalRefundAmount(payAmount);
        studentRefundVo.setRefundWay(3);
        studentRefundVo.setRefundLectureFrom(studentReg.getStartAmount());
        studentRefundService.saveStudentRefund(studentRefundVo,principal);

    }


    @Override
    public void setupSetupCounselor(Long courseOrderId, Long counselorId) {
        Teacher teacher = teacherService.findById(counselorId, "teacherName");
        StudentReg u = new StudentReg();
        u.setCounselorId(counselorId);
        u.setCounselorName(teacher.getTeacherName());
        u.setUpdateTime(TimeUtils.now());

        Example<StudentReg> studentRegExample = StudentReg.createExample();
        studentRegExample.createCriteria().andEqualTo("courseOrderId" , courseOrderId );
        updateSelectiveByExample(u,studentRegExample);

    }


    @Override
    public List<Long> findRegStudentIds(Long areaTeamId, Long subjectId , List<Long> periodIds, List<Long> gradeIds, List<Integer> levels, List<Long> campusIds ) {
        if(periodIds != null && periodIds.size() == 0 ){
            periodIds = null ;
        }
        if(gradeIds != null && gradeIds.size() == 0 ){
            gradeIds = null ;
        }
        if(levels != null && levels.size() == 0 ){
            levels = null ;
        }
        if(campusIds != null && campusIds.size() == 0 ){
            campusIds = null ;
        }
        return autoMapper.queryRegStudentIds( areaTeamId , subjectId , periodIds,gradeIds, levels, campusIds);
    }


    @Override
    public List<StudentReg> findListByClassIds(List<Long> classIds, Integer regStatus,String ...columns) {
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andIn("classId",classIds);
        criteria.andEqualTo("regStatus",regStatus);
        return findListByExample(example);
    }

    @Override
    public List<StudentReg> findByClassIdsStudentIds(List<Long> classIds, List<Long> studentIds) {
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andIn("classId",classIds);
        criteria.andIn("studentId",studentIds);
        criteria.andEqualTo("regStatus",0);
        criteria.andEqualTo("chargingStatus",2);
        return findListByExample(example);
    }

    @Override
    public List<StudentReg> findRegByClassIdStudentId(long classId,long studentId,List<Integer> regStatuses) {
        Example<StudentReg> example = StudentReg.createExample();
        Example.Criteria criteria=example.createCriteria();
        criteria.andEqualTo("classId",classId);
        criteria.andEqualTo("studentId",studentId);
        if (Utils.checkListNotEmpty(regStatuses)){
            criteria.andIn("regStatus", regStatuses);
        }
        example.orderBy("createTime");
        return findListByExample(example);
    }


    @Override
    public Long countBySeniorStudentRegs(Long seniorId, Long studentId, Long periodId, Long busTeamId) {
        if (seniorId==null || studentId==null || periodId==null || busTeamId==null){
            throw new NullPointerException();
        }

        Example<StudentReg> studentRegExample=StudentReg.createExample();
        Example.Criteria criteria=studentRegExample.createCriteria();
        criteria.andEqualTo("seniorId",seniorId);
        criteria.andEqualTo("studentId",studentId);
        criteria.andEqualTo("periodId",periodId);
        criteria.andEqualTo("busTeamId",busTeamId);
        criteria.andEqualTo("regStatus",0);
        return countByExample(studentRegExample);
    }


    @Override
    public List<StudentClassVo> findStudentClassList(List<Long> studentIds, List<Long> classIds) {
        if (Utils.checkListEmpty(studentIds) || Utils.checkListEmpty(classIds)){
            return  Collections.EMPTY_LIST;
        }
        return autoMapper.findStudentClassList(studentIds,classIds);
    }

    @Override
    public List<StudentReg> findByCourseOrderIds(List<Long> courseOrderIds,String ...columns) {
        if (Utils.checkListEmpty(courseOrderIds) ){
            return  Collections.EMPTY_LIST;
        }
        Example<StudentReg> studentRegExample=StudentReg.createExample();
        studentRegExample.createCriteria().andIn("courseOrderId",courseOrderIds);
        if (columns!=null){
            studentRegExample.selectProperties(columns);
        }
        return this.findListByExample(studentRegExample);
    }

    @Override
    public boolean hadReg(Long studentId, Long classId, int startLecture, int endLecture) {
        return hadReg(findStudentReg(classId,studentId) , startLecture,endLecture );
    }

    @Override
    public boolean hadReg(List<StudentReg> studentRegList , Integer startLecture , Integer endLecture  ){

        if(studentRegList == null || studentRegList.isEmpty() ){
            return false ;
        }

        for(StudentReg studentReg : studentRegList ){
            if( ( startLecture >= studentReg.getStartAmount() && startLecture <= studentReg.getEndAmount()) || ( endLecture >= studentReg.getStartAmount() && endLecture <= studentReg.getEndAmount()) ){
                return true ;
            }
        }
        return false ;
    }

    @Override
    public List<StudentReg> findReadListByClassIdsStudentId(List<Long> classIds, Long studentId) {
        Validate.notNull(studentId);
        Example<StudentReg> example = StudentReg.createExample();
        example.createCriteria().andEqualTo("regStatus" , 0 ).andIn("classId",classIds).andEqualTo("studentId",studentId );
        return findListByExample(example) ;
    }

    @Override
    public List<StudentReg> findRegListByStudentIdsPeriodIdsRegStatuses(List<Long> studentIds, List<Long> periodIds, List<Integer> regStatuses, String... columns) {
        if (Utils.isEmpty(studentIds) || Utils.isEmpty(periodIds) || Utils.isEmpty(regStatuses)){
            return  Collections.EMPTY_LIST;
        }
        Example<StudentReg> example=StudentReg.createExample();
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("studentId",studentIds);
        criteria.andIn("periodId",periodIds);
        criteria.andIn("regStatus",regStatuses);
        if (columns!=null){
            example.selectProperties(columns);
        }
        return this.findListByExample(example);
    }


}